// 数据导出，目前支持数据的类型：json
package parser

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
	"text/template"

	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/pquerna/ffjson/ffjson"
)

var clientFiles []string     // A3 逗号分隔的文件名称 客户端代码统一生成2份
var clientNick string        // 客户端别名
var clientJson string        // 客户端特有的json格式
var clientJsonSysLang string // 特殊客户端特有的json格式

func Reset() {
	clientFiles = []string{}
	clientNick = ""
	clientJson = "" // 客户端专用格式
	clientJsonSysLang = ""
	serverFiles = []string{}
}

// 数据解析单表
func DataSheetParseClient(rows [][]string, sheet string) (data []interface{}, err string) {
	// 提前创建好底层数组，避免复制
	data = make([]interface{}, 0, len(rows))
	if len(rows) == 0 {
		return
	}

	columnNum := len(rows[0])
	rowNum := len(rows)

	// 元数据列表
	metaList := make([]*DataMeta, columnNum)

	// 前4行结构定义
	for j := 1; j < columnNum; j++ {
		// 发现有 "END" 标识 直接返回
		if rows[3][j] == "END" {
			columnNum = j + 1
			break
		}

		meta := &DataMeta{
			// NameType: rows[0][j],
			DataType: rows[2][j],
			Name:     Ucfirst(strings.TrimPrefix(rows[1][j], "_")),
			Comment:  rows[0][j],
		}
		metaList[j] = meta
	}

	// 5行及以后数据
	for i := 4; i < rowNum; i++ {

		// 一行数据
		var item *Smap
		item, err = DataRowParseClient(rows[i], metaList, columnNum)
		if err != "" {
			err = fmt.Sprintf("第%d行,%v", i, err)
			return
		}

		// 客户端格式
		str := ToSortedMapJson(item)
		if str != "" {
			clientJson += str + "\n"
			clientJsonSysLang += str + ","
		}

		// 最后一行数据用"END"标识
		if rows[i][0] == "END" {
			break
		}

	}

	return
}

// 一行数据解析
func DataRowParseClient(row []string, metaList []*DataMeta, columnNum int) (item *Smap, err string) {
	item = &Smap{}
	for c := 1; c < columnNum; c++ {

		meta := metaList[c]
		// 过滤没有字段名字的行
		if meta == nil || meta.Name == "" {
			continue
		}

		var scalar interface{}
		scalar, err = DataCellParse(meta, row[c])
		if err != "" {
			err = fmt.Sprintf("列名:%v] 错误:%v", meta.Name, err)
			return
		}
		item.Put(meta.Name, scalar)
	}
	return
}

// 导出客户端
func DataParseSysLang(filetype string, sheetSlice []string, xlsx *excelize.File) (ret string) {
	mSheet := make(map[string]string) // sheetName Json
	Reset()

	// 客户端专用json格式
	var tmpClientJsonFormat string

	for _, sheet := range sheetSlice {
		rows := xlsx.GetRows(sheet)
		if len(rows) <= 0 {
			ret = fmt.Sprintf("[DataParse:sheet:%v] 表不存在或者为空 len(rows):%v", sheet, len(rows))
			return
		}
		// 客户端
		_, err := DataSheetParseClient(rows, sheet)
		if err != "" {
			err = fmt.Sprintf("[客户端sheet:%v,%v", sheet, err)
			return err
		}

		// 客户端cs文件格式专用数据
		clientJsonSysLang = "[" + strings.TrimRight(clientJsonSysLang, ",") + "]"
		mSheet[sheet] = clientJsonSysLang
		clientJsonSysLang = ""
	}

	var fileName string
	if filetype == "SystemLanguage" {
		fileName = "ESystemLanguage"
	} else if filetype == "ConfigValue" {
		fileName = "EConfigValue"
	}

	var content string
	if fileName == "ESystemLanguage" {
		type sysLang struct {
			Id   int
			Name string
			Desc string
		}
		for _, sheet := range sheetSlice {
			var list []sysLang
			err := json.Unmarshal([]byte(mSheet[sheet]), &list)
			if err != nil {
				return err.Error()
			}

			content += fmt.Sprintf("//----------------------%v------------------------------------------------------------\n\n", sheet)
			// 客户端专用
			for _, item := range list {
				desc := strings.ReplaceAll(item.Desc, "\n", "")
				desc = strings.ReplaceAll(desc, "\r", "")
				content += "\t\t" // tab
				content += fmt.Sprintf("/// <summary> %s </summary>\n", desc)
				content += "\t\t" // tab
				content += fmt.Sprintf("%v = %d,\n", item.Name, item.Id)

				tmpClientItem := &Smap{}
				tmpClientItem.Put("Id", item.Id)
				// tmpClientItem.Put("name", item.Name)
				tmpClientItem.Put("Desc", item.Desc)
				str := ToSortedMapJson(tmpClientItem)
				if str != "" {
					tmpClientJsonFormat += str + "\n"
				}

			}

		}
	} else if fileName == "EConfigValue" {
		type configV struct {
			Id        int
			Name      string
			Value     string
			Desc      string
			ValueType string
		}
		for _, sheet := range sheetSlice {
			var list []configV
			err := json.Unmarshal([]byte(mSheet[sheet]), &list)
			if err != nil {
				return err.Error()
			}

			content += fmt.Sprintf("//----------------------%v------------------------------------------------------------\n\n", sheet)
			// 客户端专用

			for _, item := range list {
				desc := strings.ReplaceAll(item.Desc, "\n", "")
				desc = strings.ReplaceAll(desc, "\r", "")
				content += "\t\t" // tab
				content += fmt.Sprintf("/// <summary> %s </summary>\n", desc)
				content += "\t\t" // tab
				content += fmt.Sprintf("%v = %d,\n", item.Name, item.Id)

				var value interface{}
				var err error
				if item.ValueType == "int" {
					value, err = strconv.Atoi(item.Value)
					if err != nil {
						return fmt.Sprintf("ParserInt错误,ID:%d,err:%v", item.Id, err)
					}
				} else if item.ValueType == "float" {
					value, err = strconv.ParseFloat(item.Value, 10)
					if err != nil {
						return fmt.Sprintf("ParserFloat错误,ID:%d,err:%v", item.Id, err)
					}
				} else if item.ValueType == "string" || item.ValueType == "String" {
					value = fmt.Sprintf("%s", item.Value)
				}

				tmpClientItem := &Smap{}
				tmpClientItem.Put("Id", item.Id)
				// tmpClientItem.Put("name", item.Name)
				tmpClientItem.Put("Value", value)
				str := ToSortedMapJson(tmpClientItem)
				if str != "" {
					tmpClientJsonFormat += str + "\n"
				}

			}

		}
	}

	outFilename := fmt.Sprintf("%s\\%s.cs", clientCodeOutputPath+"Hotfix", fileName)

	outFile, err := os.Create(outFilename)
	defer outFile.Close()
	if err != nil {
		return err.Error()
	}

	tmpl, err := template.New("struct_gen").Funcs(funcMap).Parse(cstplSysLang)
	if err != nil {
		return err.Error()
	}
	err = tmpl.Execute(outFile, &StructPkg{PkgName: fileName, Name: content})
	if err != nil {
		return err.Error()
	}

	// SystemLanguage json client

	// outJsonFilename := fmt.Sprintf("%s\\%s.txt", clientDataOutputPath+"", filetype)

	// outJsonFile, err := os.Create(outJsonFilename)
	// defer outJsonFile.Close()
	// if err != nil {
	// 	return err.Error()
	// }

	// _, err = outJsonFile.Write([]byte(tmpClientJsonFormat))
	// if err != nil {
	// 	return err.Error()
	// }

	// end  SystemLanguage json client

	return

}

// 导出服务端
func DataParseSysLangServer(sheetSlice []string, xlsx *excelize.File) (ret string) {
	mSheet := make(map[string]string) // sheetName Json
	Reset()

	for _, sheet := range sheetSlice {
		rows := xlsx.GetRows(sheet)
		if len(rows) <= 0 {
			ret = fmt.Sprintf("[DataParse:sheet:%v] 表不存在或者为空 len(rows):%v", sheet, len(rows))
			return
		}
		// 客户端
		_, err := DataSheetParseClient(rows, sheet)
		if err != "" {
			err = fmt.Sprintf("[客户端sheet:%v,%v", sheet, err)
			return err
		}
		clientJsonSysLang = "[" + strings.TrimRight(clientJsonSysLang, ",") + "]"
		mSheet[sheet] = clientJsonSysLang
		clientJsonSysLang = ""
	}

	var fileName string = "configvalue"

	type configvalue struct {
		Id        int
		Name      string
		ValueType string
		Value     string
		RowData   int // 服务器只看2,3的 客户端只看1，3的
		Desc      string
	}

	// server
	var mCfgValue = make(map[int]interface{})
	var content string

	// 全部数据
	for _, sheet := range sheetSlice {
		var list []configvalue
		err := json.Unmarshal([]byte(mSheet[sheet]), &list)
		if err != nil {
			return err.Error()
		}

		// server
		content += fmt.Sprintf("// %s \n", sheet)
		for _, item := range list {

			// 服务器数据
			if item.RowData != 2 && item.RowData != 3 {
				continue
			}

			desc := strings.ReplaceAll(item.Desc, "\n", "")
			desc = strings.ReplaceAll(desc, "\r", "")
			var value interface{}
			var err error
			if item.ValueType == "int" {
				value, err = strconv.Atoi(item.Value)
				if err != nil {
					return fmt.Sprintf("ParserInt错误,ID:%d,err:%v", item.Id, err)
				}
				mCfgValue[item.Id] = value
			} else if item.ValueType == "float" {
				value, err = strconv.ParseFloat(item.Value, 10)
				if err != nil {
					return fmt.Sprintf("ParserFloat错误,ID:%d,err:%v", item.Id, err)
				}
				mCfgValue[item.Id] = value
			} else if item.ValueType == "string" || item.ValueType == "String" {
				value = "`" + item.Value + "`"
				mCfgValue[item.Id] = item.Value
			}
			content += "\t" // tab
			content += fmt.Sprintf("%s = %d // %s \n", item.Name, item.Id, desc)
		}

	}

	// configValue json server
	jsonBytes, err := ffjson.Marshal(mCfgValue)
	if err != nil {
		return fmt.Sprintf("configValue json server : %v", err)
	}

	var out bytes.Buffer
	err = json.Indent(&out, jsonBytes, "", "\t")

	if err != nil {
		return err.Error()
	}

	outJsonFilename := fmt.Sprintf("%s\\%s.json", dataOutputPath+"Common", fileName)

	outJsonFile, err := os.Create(outJsonFilename)
	defer outJsonFile.Close()
	if err != nil {
		return err.Error()
	}

	_, err = outJsonFile.Write(out.Bytes())
	if err != nil {
		return err.Error()
	}

	// end  configValue json server

	outFilename := fmt.Sprintf("%s\\%s.go", codeOutputPath+"Common", fileName)

	outFile, err := os.Create(outFilename)
	defer outFile.Close()
	if err != nil {
		return err.Error()
	}

	tmpl, err := template.New("struct_gen").Funcs(funcMap).Parse(tplConfigValue)
	if err != nil {
		return err.Error()
	}
	err = tmpl.Execute(outFile, &StructPkg{PkgName: fileName, Name: content})
	if err != nil {
		return err.Error()
	}

	return

}
